using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using WeatherApp.Models;

namespace WeatherApp.Services
{
    public class WeatherService : IWeatherService
    {
        private readonly HttpClient _httpClient;
        private readonly IMemoryCache _cache;
        private readonly IDataService _dataService;
        private readonly ILogger<WeatherService> _logger;
        private readonly IConfiguration _configuration;

        public WeatherService(
            HttpClient httpClient, 
            IMemoryCache cache, 
            IDataService dataService,
            ILogger<WeatherService> logger,
            IConfiguration configuration)
        {
            _httpClient = httpClient;
            _cache = cache;
            _dataService = dataService;
            _logger = logger;
            _configuration = configuration;
        }

        public async Task<WeatherInfo> GetCurrentWeatherAsync(string city)
        {
            var cacheKey = $"current_weather_{city}";
            
            if (_cache.TryGetValue(cacheKey, out WeatherInfo? cachedWeather))
            {
                return cachedWeather!;
            }

            try
            {
                var apiKey = _configuration["WeatherApi:ApiKey"];
                var baseUrl = _configuration["WeatherApi:BaseUrl"] ?? "https://api.weatherapi.com/v1";

                if (string.IsNullOrEmpty(apiKey))
                {
                    var mockWeather = GetMockCurrentWeather(city);
                    await _dataService.SaveWeatherRecordAsync(mockWeather);
                    
                    var cacheTimeout = TimeSpan.Parse(_configuration["WeatherApi:CacheTimeout:CurrentWeather"] ?? "00:30:00");
                    _cache.Set(cacheKey, mockWeather, cacheTimeout);
                    
                    return mockWeather;
                }

                var url = $"{baseUrl}/current.json?key={apiKey}&q={Uri.EscapeDataString(city)}&aqi=yes";
                var response = await _httpClient.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    var json = await response.Content.ReadAsStringAsync();
                    var weatherData = JsonConvert.DeserializeObject<dynamic>(json);
                    
                    var weather = new WeatherInfo
                    {
                        City = city,
                        Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                        Weather = weatherData?.current?.condition?.text?.ToString() ?? "未知",
                        Temperature = $"{weatherData?.current?.temp_c?.ToString()}°C",
                        Humidity = $"{weatherData?.current?.humidity?.ToString()}%",
                        WindDirection = $"{weatherData?.current?.wind_dir?.ToString()}风",
                        WindPower = $"{weatherData?.current?.wind_kph?.ToString()} km/h",
                        AirQuality = GetAirQualityText(weatherData?.current?.air_quality?.us_epa_index?.ToString()),
                        UvIndex = weatherData?.current?.uv?.ToString() ?? "0",
                        Visibility = $"{weatherData?.current?.vis_km?.ToString()} km",
                        Pressure = $"{weatherData?.current?.pressure_mb?.ToString()} mb",
                        FeelsLike = $"{weatherData?.current?.feelslike_c?.ToString()}°C"
                    };

                    await _dataService.SaveWeatherRecordAsync(weather);

                    var cacheTimeout = TimeSpan.Parse(_configuration["WeatherApi:CacheTimeout:CurrentWeather"] ?? "00:30:00");
                    _cache.Set(cacheKey, weather, cacheTimeout);

                    return weather;
                }
                else
                {
                    var mockWeather = GetMockCurrentWeather(city);
                    await _dataService.SaveWeatherRecordAsync(mockWeather);
                    return mockWeather;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取天气信息失败: {City}", city);
                var mockWeather = GetMockCurrentWeather(city);
                await _dataService.SaveWeatherRecordAsync(mockWeather);
                return mockWeather;
            }
        }

        public async Task<WeatherForecast> GetWeatherForecastAsync(string city)
        {
            var cacheKey = $"forecast_{city}";
            
            if (_cache.TryGetValue(cacheKey, out WeatherForecast? cachedForecast))
            {
                return cachedForecast!;
            }

            var mockForecast = GetMockForecast(city);
            var cacheTimeout = TimeSpan.Parse(_configuration["WeatherApi:CacheTimeout:Forecast"] ?? "01:00:00");
            _cache.Set(cacheKey, mockForecast, cacheTimeout);
            return mockForecast;
        }

        public async Task<List<LifeIndex>> GetLifeIndexAsync(string city)
        {
            var cacheKey = $"life_index_{city}";
            
            if (_cache.TryGetValue(cacheKey, out List<LifeIndex>? cachedIndices))
            {
                return cachedIndices!;
            }

            var mockIndices = GetMockLifeIndices();
            var cacheTimeout = TimeSpan.Parse(_configuration["WeatherApi:CacheTimeout:LifeIndex"] ?? "02:00:00");
            _cache.Set(cacheKey, mockIndices, cacheTimeout);
            return mockIndices;
        }

        public async Task<List<CityInfo>> SearchCitiesAsync(string keyword)
        {
            var cacheKey = $"city_search_{keyword}";
            
            if (_cache.TryGetValue(cacheKey, out List<CityInfo>? cachedCities))
            {
                return cachedCities!;
            }

            var mockCities = GetMockCities(keyword);
            var cacheTimeout = TimeSpan.Parse(_configuration["WeatherApi:CacheTimeout:CitySearch"] ?? "24:00:00");
            _cache.Set(cacheKey, mockCities, cacheTimeout);
            return mockCities;
        }

        public async Task<CityInfo?> GetCityByLocationAsync(double latitude, double longitude)
        {
            return GetMockCityByLocation(latitude, longitude);
        }

        #region 私有方法

        private WeatherInfo GetMockCurrentWeather(string city)
        {
            var random = new Random();
            var temperatures = new[] { 15, 18, 22, 25, 28, 30 };
            var weathers = new[] { "晴", "多云", "阴", "小雨", "中雨", "大雨" };
            var windDirections = new[] { "东风", "南风", "西风", "北风", "东南风", "西南风", "东北风", "西北风" };

            return new WeatherInfo
            {
                City = city,
                Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                Weather = weathers[random.Next(weathers.Length)],
                Temperature = $"{temperatures[random.Next(temperatures.Length)]}°C",
                Humidity = $"{random.Next(40, 90)}%",
                WindDirection = windDirections[random.Next(windDirections.Length)],
                WindPower = $"{random.Next(1, 20)} km/h",
                AirQuality = "良",
                UvIndex = $"{random.Next(1, 10)}",
                Visibility = $"{random.Next(5, 15)} km",
                Pressure = $"{random.Next(1000, 1030)} mb",
                FeelsLike = $"{random.Next(15, 32)}°C"
            };
        }

        private WeatherForecast GetMockForecast(string city)
        {
            var random = new Random();
            var forecast = new WeatherForecast
            {
                City = city,
                Daily = new List<DailyForecast>(),
                Hourly = new List<HourlyForecast>()
            };

            var weathers = new[] { "晴", "多云", "阴", "小雨", "中雨" };
            var windDirections = new[] { "东风", "南风", "西风", "北风" };

            for (int i = 0; i < 5; i++)
            {
                var maxTemp = random.Next(20, 35);
                var minTemp = random.Next(10, 25);
                
                forecast.Daily.Add(new DailyForecast
                {
                    Date = DateTime.Now.AddDays(i).ToString("yyyy-MM-dd"),
                    Weather = weathers[random.Next(weathers.Length)],
                    MaxTemp = $"{maxTemp}°C",
                    MinTemp = $"{minTemp}°C",
                    Precipitation = $"{random.Next(0, 50)}mm",
                    WindDirection = windDirections[random.Next(windDirections.Length)],
                    WindPower = $"{random.Next(1, 15)} km/h"
                });
            }

            return forecast;
        }

        private List<LifeIndex> GetMockLifeIndices()
        {
            return new List<LifeIndex>
            {
                new LifeIndex { Type = "穿衣指数", Level = "长袖衬衫", Description = "天气舒适，建议穿长袖衬衫、薄外套等" },
                new LifeIndex { Type = "运动指数", Level = "适宜", Description = "天气晴朗，非常适合户外运动" },
                new LifeIndex { Type = "洗车指数", Level = "较适宜", Description = "天气较好，较适宜洗车" },
                new LifeIndex { Type = "旅游指数", Level = "适宜", Description = "天气晴朗，非常适合旅游" }
            };
        }

        private List<CityInfo> GetMockCities(string keyword)
        {
            var cities = new List<CityInfo>();
            
            if (keyword.Contains("北京") || keyword.Contains("beijing"))
            {
                cities.Add(new CityInfo { Name = "北京", Code = "101010100", Province = "北京", Latitude = 39.9042, Longitude = 116.4074 });
            }
            if (keyword.Contains("上海") || keyword.Contains("shanghai"))
            {
                cities.Add(new CityInfo { Name = "上海", Code = "101020100", Province = "上海", Latitude = 31.2304, Longitude = 121.4737 });
            }
            if (keyword.Contains("广州") || keyword.Contains("guangzhou"))
            {
                cities.Add(new CityInfo { Name = "广州", Code = "101280101", Province = "广东", Latitude = 23.1291, Longitude = 113.2644 });
            }
            if (keyword.Contains("深圳") || keyword.Contains("shenzhen"))
            {
                cities.Add(new CityInfo { Name = "深圳", Code = "101280601", Province = "广东", Latitude = 22.5431, Longitude = 114.0579 });
            }

            return cities;
        }

        private CityInfo GetMockCityByLocation(double latitude, double longitude)
        {
            if (latitude > 39 && latitude < 40 && longitude > 116 && longitude < 117)
            {
                return new CityInfo { Name = "北京", Code = "101010100", Province = "北京", Latitude = latitude, Longitude = longitude };
            }
            else if (latitude > 31 && latitude < 32 && longitude > 121 && longitude < 122)
            {
                return new CityInfo { Name = "上海", Code = "101020100", Province = "上海", Latitude = latitude, Longitude = longitude };
            }
            else
            {
                return new CityInfo { Name = "未知城市", Code = "000000000", Province = "未知", Latitude = latitude, Longitude = longitude };
            }
        }

        private string GetAirQualityText(string? index)
        {
            return index switch
            {
                "1" => "优",
                "2" => "良",
                "3" => "轻度污染",
                "4" => "中度污染",
                "5" => "重度污染",
                "6" => "严重污染",
                _ => "未知"
            };
        }

        #endregion
    }
} 